
#include "hsocket_client.h"


#define SETCONNECTFLAGBIT       BIT0
#define CONNECTEDFLAGBIT        BIT1
#define DISCONNECTEDFLAGBIT     BIT2

static void hsocket_client_task(void *param);


hsocket_client_wrap *hsocket_client_warp_create(int rec_buffer_size, void (*cb)(char *data, int len)) {
    hsocket_client_wrap *res = malloc(sizeof(hsocket_client_wrap));
    if (res == NULL) {
        return NULL;
    }
    res->rec_buffer = malloc(rec_buffer_size);
    if (res->rec_buffer == NULL) {
        free(res);
        return NULL;
    }
    res->rec_buffer_size = rec_buffer_size;
    res->event = xEventGroupCreate();
    if (pdPASS != xTaskCreate(hsocket_client_task, "hsocket_client_task", 4096, (void *)res, tskIDLE_PRIORITY, &(res->task))) {
        free(res);
        return NULL;
    }
    res->cb = cb;
    return res;
}


void hsocket_client_warp_delete(hsocket_client_wrap *warp) {
    if (warp == NULL) {
        return;
    }
    vTaskDelete(warp->task);
    vEventGroupDelete(warp->event);
    close(warp->sock);
    free(warp->rec_buffer);
    free(warp);
    warp = NULL;
}


bool hsocket_client_is_connected(hsocket_client_wrap *warp) {
    EventBits_t event_value = xEventGroupWaitBits(warp->event,
                                    CONNECTEDFLAGBIT,
                                    pdFALSE,
                                    pdFALSE,
                                    0);
    if ((event_value & CONNECTEDFLAGBIT) == CONNECTEDFLAGBIT) {
        return true;
    }
    else {
        return false;
    }
}

bool hsocket_client_wait_connect(hsocket_client_wrap *warp, TickType_t timeout) {
    EventBits_t event_value = xEventGroupWaitBits(warp->event,
                                    CONNECTEDFLAGBIT,
                                    pdFALSE,
                                    pdFALSE,
                                    timeout);
    if ((event_value & CONNECTEDFLAGBIT) == CONNECTEDFLAGBIT) {
        return true;
    }
    else {
        return false;
    }
}

bool hsocket_client_wait_disconnect(hsocket_client_wrap *warp, TickType_t timeout) {
    EventBits_t event_value = xEventGroupWaitBits(warp->event,
                                    DISCONNECTEDFLAGBIT,
                                    pdFALSE,
                                    pdFALSE,
                                    timeout);
    if ((event_value & DISCONNECTEDFLAGBIT) == DISCONNECTEDFLAGBIT) {
        return true;
    }
    else {
        return false;
    }
}

void hsocket_client_connect(hsocket_client_wrap *warp) {
    close(warp->sock);
    xEventGroupSetBits(warp->event, SETCONNECTFLAGBIT);
}

void hsocket_client_disconnect(hsocket_client_wrap *warp) {
    xEventGroupClearBits(warp->event, SETCONNECTFLAGBIT);
    close(warp->sock);
}

bool hsocket_client_send(hsocket_client_wrap *warp, const uint8_t *data, int len, TickType_t timeout) {
    if (hsocket_client_wait_connect(warp, timeout)) {
        send(warp->sock, data, len, 0);
        HLOGI("hsocket", "send socket %d",warp->sock);
        return true;
    }
    else {
        return false;
    }
}

static void hsocket_client_task(void *param) {
    hsocket_client_wrap *client = (hsocket_client_wrap *)param;

    int err;
    struct sockaddr_in dest_addr;
    EventBits_t event_value;

    while(true) {
        //等待收到连接event才继续下面的连接逻辑
        event_value = xEventGroupWaitBits(client->event,
                                    SETCONNECTFLAGBIT,
                                    pdFALSE,
                                    pdFALSE,
                                    portMAX_DELAY);
        if ((event_value & SETCONNECTFLAGBIT) != SETCONNECTFLAGBIT) {
            continue;
        }

        //连接socket
        HLOGI("hsocket", "%d:try connect:%s:%d", (int)client->task, client->param.ip, client->param.port);
        dest_addr.sin_addr.s_addr = inet_addr(client->param.ip);
        dest_addr.sin_family = AF_INET;
        dest_addr.sin_port = htons(client->param.port);
        hwifi_wait_gotip(portMAX_DELAY);
        close(client->sock);    //无论是否存在socket，都close一遍确认
        client->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
        if (client->sock < 0) {
            HLOGE("hsocket", "%d:socket<0", (int)client->task);
            vTaskDelay(10); //避免频繁重连
            continue;
        }
        err = connect(client->sock, (struct sockaddr*)&dest_addr, sizeof(struct sockaddr_in6));
        if (err != 0) { //连接失败，跳出至循环初始的位置
            HLOGE("hsocket", "%d:socket %d connect fail", (int)client->task, client->sock);
            continue;
        }
        //连接成功，继续接下来的逻辑
        HLOGI("hsocket", "%d:socket %d connect successful", (int)client->task, client->sock);
            
        xEventGroupClearBits(client->event, DISCONNECTEDFLAGBIT);
        xEventGroupSetBits(client->event, CONNECTEDFLAGBIT);
        while(true) {       //接收socket数据
            int len = recv(client->sock, client->rec_buffer, client->rec_buffer_size, 0);
            if (len <= 0) { //recv返回且数据量不大于0，表明socket断开
                xEventGroupClearBits(client->event, CONNECTEDFLAGBIT);
                xEventGroupSetBits(client->event, DISCONNECTEDFLAGBIT);
                HLOGI("hsocket", "%d: server socket closed", (int)client->task);
                vTaskDelay(10); //避免频繁重连
                break;
            }
            client->rec_buffer[len] = '\0';
            if (client->cb != NULL) {
                (*(client->cb))(client->rec_buffer, len);
            }
            HLOGI("hsocket", "socket %d recv %d chars:%s", client->sock, len, client->rec_buffer);
        }
    }
}




